﻿using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

using System;
using System.IO;
using System.Reflection;
using System.Text.Json.Serialization;

using Xc.DataAccess.Core;
using Xc.Views.Core.Properties;
using System.Linq;
using Xc.DataAccess.Core.Services;
using Microsoft.Extensions.Options;

namespace Xc.Views.Core
{

    /// <summary>
    /// 应用程序启动类
    /// </summary>
    /// <typeparam name="TAppSetting"></typeparam>
    public class ApplicationBooster<TAppSetting> : StartupCore, IApplicationBooster<TAppSetting>
where TAppSetting : class,new()
    {
        /// <summary>
        /// 应用程序启动类
        /// </summary>
        /// <param name="applicationName"></param>
        /// <param name="applicationVersion"></param>
        public ApplicationBooster(string applicationName, string applicationVersion) : base(applicationName, applicationVersion)
        {

        }

        /// <summary>
        /// 启抽象类
        /// </summary>
        public ApplicationBooster()
        {

        }

        /// <summary>
        /// 添加服务
        /// </summary>
        /// <param name="serviceDescriptors"></param>
        protected virtual void BeforeBuild(IServiceCollection serviceDescriptors)
        {

        }
        /// <summary>
        /// 获取配置服务总线
        /// </summary>
        /// <returns></returns>
        public virtual void ConfigureServices(IServiceCollection services)
        {
            ConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
            CopyAppSetting();
            AddAppSettingFile(configurationBuilder);
            Configuration = configurationBuilder.Build();
            services.AddConverterService();
            BeforeBuild(services);
            services.AddSingleton<IApplicationBooster<TAppSetting>>(this);
            var builder = services.Configure<TAppSetting>(Configuration.Bind);
            services.AddSingleton(builder);
        }
        /// <summary>
        /// 配置总线
        /// </summary>
        protected IConfiguration Configuration { get; private set; }
        /// <summary>
        /// 是否已完成初始化
        /// </summary>
        public bool IsInizlized { get;private set; }
        /// <summary>
        /// 获取主UI元素
        /// </summary>
        /// <typeparam name="TUiElement"></typeparam>
        /// <returns></returns>
        public virtual TUiElement GetMainElement<TUiElement>()
        {
            if (IsInizlized == false) 
            {
                var services = new ServiceCollection();

                ConfigureServices(services);
                serviceProvider = services.BuildServiceProvider();
                AfterBuild(serviceProvider);
                IsInizlized = true;
            }
            return serviceProvider.GetService<TUiElement>();
        }
        /// <summary>
        /// 服务总线
        /// </summary>
        protected IServiceProvider serviceProvider { get; private set; }
        /// <summary>
        /// 编译完成后执行
        /// </summary>
        /// <param name="serviceProvider"></param>
        protected virtual void AfterBuild(IServiceProvider serviceProvider)
        {
        }
        /// <summary>
        /// 添加配置信息
        /// </summary>
        /// <param name="configurationBuilder"></param>
        protected virtual void AddAppSettingFile(ConfigurationBuilder configurationBuilder)
        {
            if (File.Exists(ApplicationSettingFileName))
            {
                configurationBuilder.AddJsonFile(ApplicationSettingFileName,true,true);
            }
        }
        /// <summary>
        /// 将当前程序集下的配置文件拷贝到目标地址
        /// </summary>
        protected virtual void CopyAppSetting()
        {

            var attr = (BootAttribute)this.GetType().GetCustomAttributes(typeof(BootAttribute)).FirstOrDefault();
            if (attr != null)
            {
                this.ApplicationName = attr.ApplicationName;
                this.ApplicationVersion = attr.ApplicationVersion;
            }
            if (this.ApplicationName == null)
            {
                throw new ArgumentNullException(TextResource.please_add_applicationName);
            }
            var current = Path.Combine(ApplicationBaseDirectory, AppSettingName);
            if (File.Exists(current)&&!File.Exists(ApplicationSettingFileName))
            {
                File.Copy(current, ApplicationSettingFileName);
            }
        }
        /// <summary>
        /// 更新设置文件
        /// </summary>
        /// <param name="appSetting"></param>
        /// <returns></returns>
        public  Result UpdateAppSettingFile(TAppSetting appSetting)
        {
            try
            {
                var converter = serviceProvider.GetService<IConverterService>();
                switch (AppSettingFileType)
                {
                    case AppSettingFileType.Json:
                        File.WriteAllText(ApplicationSettingFileName, converter.ToJsonString(appSetting));
                        break;
                    case AppSettingFileType.Yaml:
                        File.WriteAllText(ApplicationSettingFileName, converter.ToYamlString(appSetting));
                        break;
                    case AppSettingFileType.Xml:
                        File.WriteAllText(ApplicationSettingFileName, converter.ToXmlString(appSetting));
                        break;
                    case AppSettingFileType.Bin:
                        var res = converter.ToBinaryArray(appSetting);
                        if (res.IsError)
                        {
                            return Result.Reject(res.Message);
                        }
                        File.WriteAllBytes(ApplicationSettingFileName, res.Data);
                        break;

                    default:
                        break;
                }
                var setting= serviceProvider.GetService<IOptionsSnapshot<TAppSetting>>();
                return Result.Accept(TextResource.setting_info_write_successful);
            }
            catch (Exception err)
            {
                return Result.Reject(err.Message);
            }

        }
    }
}
